#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
云客户端缓存管理器
提供云存储客户端的缓存、获取和清理功能，避免重复创建客户端
"""

import time
import threading
import logging
from typing import Dict, Optional, Any, Tuple
from datetime import datetime, timedelta
from collections import defaultdict

import sys
import os

# 添加项目根目录到 Python 路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

try:
    from clouds_sdk.cloud_factory import CloudFactory
except ImportError:
    try:
        # 尝试相对导入
        from .cloud_factory import CloudFactory
    except ImportError:
        # 如果导入失败，提供一个模拟的工厂类
        class CloudFactory:
            @staticmethod
            def create_client(**kwargs):
                raise NotImplementedError("CloudFactory not available")
            
            @staticmethod
            def create_client_with_token(**kwargs):
                raise NotImplementedError("CloudFactory not available")

try:
    from clouds_sdk.auth_manager import get_auth_manager, AuthStatus
except ImportError:
    try:
        # 尝试相对导入
        from .auth_manager import get_auth_manager, AuthStatus
    except ImportError:
        # 如果导入失败，提供默认实现
        def get_auth_manager():
            return None
        
        class AuthStatus:
            VALID = "valid"
            INVALID = "invalid"
            EXPIRED = "expired"


class CachedClient:
    """缓存的客户端包装类"""
    
    def __init__(self, client, account_info: Dict[str, Any], cache_time: float = None):
        self.client = client
        self.account_info = account_info
        self.cache_time = cache_time or time.time()
        self.last_access_time = self.cache_time
        self.access_count = 0
        self.is_valid = True
    
    def access(self):
        """记录访问"""
        self.last_access_time = time.time()
        self.access_count += 1
    
    def is_expired(self, max_age: int = 3600) -> bool:
        """检查是否过期
        
        Args:
            max_age: 最大缓存时间（秒），默认1小时
        """
        return time.time() - self.cache_time > max_age
    
    def is_idle(self, idle_timeout: int = 1800) -> bool:
        """检查是否空闲过久
        
        Args:
            idle_timeout: 空闲超时时间（秒），默认30分钟
        """
        return time.time() - self.last_access_time > idle_timeout
    
    def check_login_status(self) -> bool:
        """检查登录状态"""
        try:
            if not self.is_valid:
                return False
            return self.client.check_login_status_only()
        except Exception:
            self.is_valid = False
            return False
    
    def get_cache_info(self) -> Dict[str, Any]:
        """获取缓存信息"""
        return {
            'account_id': self.account_info.get('id'),
            'account_name': self.account_info.get('cloud_account'),
            'provider': self.account_info.get('cloud_provider'),
            'cache_time': datetime.fromtimestamp(self.cache_time).isoformat(),
            'last_access_time': datetime.fromtimestamp(self.last_access_time).isoformat(),
            'access_count': self.access_count,
            'is_valid': self.is_valid,
            'is_logged_in': self.check_login_status()
        }


class ClientCacheManager:
    """云客户端缓存管理器
    
    功能：
    1. 缓存已创建的云存储客户端
    2. 自动清理过期和无效的客户端
    3. 支持按用户、账号维度的缓存隔离
    4. 提供缓存统计和监控
    """
    
    def __init__(self, max_cache_size: int = 100, max_age: int = 3600, 
                 idle_timeout: int = 1800, cleanup_interval: int = 300):
        """
        初始化缓存管理器
        
        Args:
            max_cache_size: 最大缓存数量
            max_age: 最大缓存时间（秒）
            idle_timeout: 空闲超时时间（秒）
            cleanup_interval: 清理间隔（秒）
        """
        self.max_cache_size = max_cache_size
        self.max_age = max_age
        self.idle_timeout = idle_timeout
        self.cleanup_interval = cleanup_interval
        
        # 缓存存储：{user_id: {account_id: CachedClient}}
        self._cache: Dict[int, Dict[int, CachedClient]] = defaultdict(dict)
        
        # 线程锁
        self._lock = threading.RLock()
        
        # 统计信息
        self._stats = {
            'hit_count': 0,
            'miss_count': 0,
            'create_count': 0,
            'evict_count': 0,
            'cleanup_count': 0
        }
        
        # 日志
        self.logger = logging.getLogger('ClientCacheManager')
        
        # 启动清理线程
        self._cleanup_thread = None
        self._stop_cleanup = False
        self._start_cleanup_thread()
    
    def _start_cleanup_thread(self):
        """启动清理线程"""
        def cleanup_worker():
            while not self._stop_cleanup:
                try:
                    time.sleep(self.cleanup_interval)
                    if not self._stop_cleanup:
                        self._cleanup_expired_clients()
                except Exception as e:
                    self.logger.error(f"清理线程异常: {e}")
        
        self._cleanup_thread = threading.Thread(target=cleanup_worker, daemon=True)
        self._cleanup_thread.start()
        self.logger.info("客户端缓存清理线程已启动")
    
    def _generate_cache_key(self, user_id: int, account_id: int) -> Tuple[int, int]:
        """生成缓存键"""
        return (user_id, account_id)
    
    def get_client(self, user_id: int, account_info: Dict[str, Any], 
                   auto_login: bool = True) -> Optional[Any]:
        """获取云存储客户端
        
        Args:
            user_id: 用户ID
            account_info: 账号信息字典，包含id, cloud_provider, cloud_account, cloud_password等
            auto_login: 是否自动登录
        
        Returns:
            云存储客户端实例，如果获取失败返回None
        """
        account_id = account_info.get('id')
        if not account_id:
            self.logger.error("账号ID不能为空")
            return None
        
        with self._lock:
            # 检查缓存
            cached_client = self._get_from_cache(user_id, account_id)
            if cached_client:
                # 检查客户端是否仍然有效
                if cached_client.check_login_status():
                    cached_client.access()
                    self._stats['hit_count'] += 1
                    self.logger.debug(f"缓存命中: user_id={user_id}, account_id={account_id}")
                    return cached_client.client
                else:
                    # 客户端无效，从缓存中移除
                    self._remove_from_cache(user_id, account_id)
                    self.logger.info(f"缓存的客户端已失效: user_id={user_id}, account_id={account_id}")
            
            # 缓存未命中，创建新客户端
            self._stats['miss_count'] += 1
            client = self._create_client(account_info, auto_login)
            if client:
                # 添加到缓存
                self._add_to_cache(user_id, account_info, client)
                self._stats['create_count'] += 1
                self.logger.info(f"创建新客户端: user_id={user_id}, account_id={account_id}")
                return client
            
            return None
    
    def _get_from_cache(self, user_id: int, account_id: int) -> Optional[CachedClient]:
        """从缓存获取客户端"""
        user_cache = self._cache.get(user_id, {})
        cached_client = user_cache.get(account_id)
        
        if cached_client:
            # 检查是否过期
            if cached_client.is_expired(self.max_age) or cached_client.is_idle(self.idle_timeout):
                self._remove_from_cache(user_id, account_id)
                return None
            
            return cached_client
        
        return None
    
    def _add_to_cache(self, user_id: int, account_info: Dict[str, Any], client):
        """添加客户端到缓存"""
        account_id = account_info.get('id')
        
        # 检查缓存大小限制
        total_cached = sum(len(user_cache) for user_cache in self._cache.values())
        if total_cached >= self.max_cache_size:
            self._evict_oldest_client()
        
        # 添加到缓存
        cached_client = CachedClient(client, account_info)
        self._cache[user_id][account_id] = cached_client
        
        self.logger.debug(f"客户端已缓存: user_id={user_id}, account_id={account_id}")
    
    def _remove_from_cache(self, user_id: int, account_id: int) -> bool:
        """从缓存移除客户端"""
        user_cache = self._cache.get(user_id, {})
        if account_id in user_cache:
            cached_client = user_cache.pop(account_id)
            
            # 清理空的用户缓存
            if not user_cache:
                self._cache.pop(user_id, None)
            
            # 尝试清理客户端资源
            try:
                if hasattr(cached_client.client, 'logout'):
                    cached_client.client.logout()
            except Exception as e:
                self.logger.warning(f"清理客户端资源失败: {e}")
            
            self.logger.debug(f"客户端已从缓存移除: user_id={user_id}, account_id={account_id}")
            return True
        
        return False
    
    def _evict_oldest_client(self):
        """驱逐最旧的客户端"""
        oldest_time = float('inf')
        oldest_key = None
        
        for user_id, user_cache in self._cache.items():
            for account_id, cached_client in user_cache.items():
                if cached_client.cache_time < oldest_time:
                    oldest_time = cached_client.cache_time
                    oldest_key = (user_id, account_id)
        
        if oldest_key:
            user_id, account_id = oldest_key
            self._remove_from_cache(user_id, account_id)
            self._stats['evict_count'] += 1
            self.logger.info(f"驱逐最旧客户端: user_id={user_id}, account_id={account_id}")
    
    def _create_client(self, account_info: Dict[str, Any], auto_login: bool = True):
        """创建云存储客户端
        
        智能登录检测逻辑：
        1. 优先使用token进行登录状态检测
        2. 如果token有效且已登录，直接使用
        3. 如果token无效或未登录，使用密码登录
        4. 密码登录成功后，获取并返回新的token信息
        """
        try:
            account_id = account_info.get('id')
            cloud_provider = account_info.get('cloud_provider')
            cloud_account = account_info.get('cloud_account')
            cloud_password = account_info.get('cloud_password')
            token_info = account_info.get('token_info')
            
            client = None
            token_login_success = False
            
            # 第一步：尝试使用token创建客户端并检测登录状态
            if token_info:
                try:
                    self.logger.debug(f"尝试使用token创建客户端: account_id={account_id}")
                    client = CloudFactory.create_client(
                        cloud_type=cloud_provider,
                        account_id=account_id,
                        username=cloud_account,
                        password=cloud_password,
                        token_info=token_info
                    )
                    
                    # 检查token登录状态
                    if client.check_login_status():
                        self.logger.info(f"Token登录状态有效: account_id={account_id}")
                        token_login_success = True
                        return client
                    else:
                        self.logger.info(f"Token登录状态无效，需要密码登录: account_id={account_id}")
                        
                except Exception as e:
                    self.logger.warning(f"使用token创建客户端失败: account_id={account_id}, error={e}")
            
            # 第二步：如果token登录失败或没有token，使用密码登录
            if not token_login_success:
                if not cloud_password:
                    self.logger.error(f"没有密码信息，无法登录: account_id={account_id}")
                    return None
                
                try:
                    self.logger.debug(f"使用密码创建客户端: account_id={account_id}")
                    client = CloudFactory.create_client(
                        cloud_type=cloud_provider,
                        account_id=account_id,
                        username=cloud_account,
                        password=cloud_password
                    )
                    
                    # 检查登录状态，如果未登录则尝试登录
                    if not client.check_login_status():
                        if auto_login:
                            self.logger.info(f"开始密码登录: account_id={account_id}")
                            if not client.login():
                                self.logger.error(f"密码登录失败: account_id={account_id}")
                                return None
                            self.logger.info(f"密码登录成功: account_id={account_id}")
                        else:
                            self.logger.warning(f"客户端未登录且不允许自动登录: account_id={account_id}")
                            return None
                    
                    # 密码登录成功，获取新的token信息并标记需要更新
                    if hasattr(client, 'get_token_info'):
                        new_token_info = client.get_token_info()
                        if new_token_info:
                            # 将新token信息添加到account_info中，供上层调用者使用
                            account_info['new_token_info'] = new_token_info
                            self.logger.info(f"获取到新的token信息: account_id={account_id}")
                    
                    return client
                    
                except Exception as e:
                    self.logger.error(f"密码登录失败: account_id={account_id}, error={e}")
                    return None
            
            return client
            
        except Exception as e:
            self.logger.error(f"创建客户端失败: account_id={account_info.get('id')}, error={e}")
            return None
    
    def _cleanup_expired_clients(self):
        """清理过期的客户端"""
        with self._lock:
            expired_keys = []
            
            for user_id, user_cache in self._cache.items():
                for account_id, cached_client in user_cache.items():
                    if (cached_client.is_expired(self.max_age) or 
                        cached_client.is_idle(self.idle_timeout) or 
                        not cached_client.check_login_status()):
                        expired_keys.append((user_id, account_id))
            
            for user_id, account_id in expired_keys:
                self._remove_from_cache(user_id, account_id)
                self._stats['cleanup_count'] += 1
            
            if expired_keys:
                self.logger.info(f"清理了 {len(expired_keys)} 个过期客户端")
    
    def invalidate_client(self, user_id: int, account_id: int) -> bool:
        """手动失效指定客户端
        
        Args:
            user_id: 用户ID
            account_id: 账号ID
        
        Returns:
            bool: 是否成功失效
        """
        with self._lock:
            return self._remove_from_cache(user_id, account_id)
    
    def invalidate_user_clients(self, user_id: int) -> int:
        """失效指定用户的所有客户端
        
        Args:
            user_id: 用户ID
        
        Returns:
            int: 失效的客户端数量
        """
        with self._lock:
            user_cache = self._cache.get(user_id, {})
            account_ids = list(user_cache.keys())
            
            count = 0
            for account_id in account_ids:
                if self._remove_from_cache(user_id, account_id):
                    count += 1
            
            return count
    
    def clear_all_cache(self) -> int:
        """清空所有缓存
        
        Returns:
            int: 清理的客户端数量
        """
        with self._lock:
            count = 0
            
            for user_id in list(self._cache.keys()):
                count += self.invalidate_user_clients(user_id)
            
            self._cache.clear()
            self.logger.info(f"清空所有缓存，共清理 {count} 个客户端")
            return count
    
    def get_cache_stats(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        with self._lock:
            total_cached = sum(len(user_cache) for user_cache in self._cache.values())
            
            return {
                'total_cached': total_cached,
                'max_cache_size': self.max_cache_size,
                'hit_count': self._stats['hit_count'],
                'miss_count': self._stats['miss_count'],
                'create_count': self._stats['create_count'],
                'evict_count': self._stats['evict_count'],
                'cleanup_count': self._stats['cleanup_count'],
                'hit_rate': self._stats['hit_count'] / max(self._stats['hit_count'] + self._stats['miss_count'], 1),
                'cache_usage': total_cached / self.max_cache_size
            }
    
    def get_cached_clients_info(self) -> Dict[str, Any]:
        """获取缓存的客户端信息"""
        with self._lock:
            clients_info = []
            
            for user_id, user_cache in self._cache.items():
                for account_id, cached_client in user_cache.items():
                    info = cached_client.get_cache_info()
                    info['user_id'] = user_id
                    clients_info.append(info)
            
            return {
                'clients': clients_info,
                'total_count': len(clients_info)
            }
    
    def shutdown(self):
        """关闭缓存管理器"""
        self.logger.info("正在关闭客户端缓存管理器...")
        
        # 停止清理线程
        self._stop_cleanup = True
        if self._cleanup_thread and self._cleanup_thread.is_alive():
            self._cleanup_thread.join(timeout=5)
        
        # 清空所有缓存
        self.clear_all_cache()
        
        self.logger.info("客户端缓存管理器已关闭")
    
    def __del__(self):
        """析构函数"""
        try:
            self.shutdown()
        except Exception:
            pass


# 全局缓存管理器实例
_global_cache_manager: Optional[ClientCacheManager] = None


def get_cache_manager() -> ClientCacheManager:
    """获取全局缓存管理器实例"""
    global _global_cache_manager
    if _global_cache_manager is None:
        _global_cache_manager = ClientCacheManager()
    return _global_cache_manager


def set_cache_manager(cache_manager: ClientCacheManager):
    """设置全局缓存管理器实例"""
    global _global_cache_manager
    if _global_cache_manager:
        _global_cache_manager.shutdown()
    _global_cache_manager = cache_manager